import moment from "moment-timezone";
import i18n from "@/lang/i18n";
import dayjs from "dayjs";
import "dayjs/locale/zh-cn";
import { Base64 } from "js-base64";
import { md5 } from "js-md5";
export { preview as $preview } from "v-preview-image";
export { default as lodash } from "lodash";
export const $dayjs = dayjs;
export const encodeByMd5 = (string: any, length = 5) => {
  if (!isNumber(string) && !isString(string)) {
    return string;
  }
  if (isNumber(string)) {
    string = string + "";
  }
  const diff_key = md5(string).slice(0, length);
  return diff_key;
};

export const encodeByBase64 = (string: any) => {
  if (!isNumber(string) && !isString(string)) {
    return string;
  }
  if (isNumber(string)) {
    string = string + "";
  }
  const chunkSize = 5000;
  const chunks = [];
  for (let i = 0; i < (string as string).length; i += chunkSize) {
    // @ts-ignore
    chunks.push(string.substr(i, chunkSize));
  }
  const encodedChunks = chunks.map((chunk) => Base64.encode(chunk));
  const encodedString = encodedChunks.join("");
  return encodedString;
};

export const decodeByBase64 = (string) => Base64.decode(string);

function extractNumber(string) {
  const numArr = string.match(/\d+/g);
  if (!numArr) return string;
  return numArr.join("");
}
function extractLetter(string) {
  const letterArr = string.match(/[a-zA-Z]/g);
  if (!letterArr) return string;
  return letterArr.join("");
}
export const $t = (string: any) => {
  const { t }: any = i18n.global;
  if (string.includes(".")) return t(string);
  const tmp_num = extractNumber(string);
  const tmp_ltr = extractLetter(string);
  const tmp_string = tmp_ltr + "." + tmp_ltr + tmp_num;
  return t(tmp_string);
};
export const getProxyT = (string: string) => computed(() => $t(string));
export const $toISOString = (time: any) => {
  return !isEmptyType(time) ? new Date(time) : undefined;
};
export const getValueByPath = function (object: any, prop: string) {
  prop = prop || "";
  const paths = prop?.split(".");
  let current = object;
  let result = null;
  for (let i = 0, j = paths.length; i < j; i++) {
    const path = paths[i];
    if (!current) break;
    if (i === j - 1) {
      result = current[path];
      break;
    }
    current = current[path];
  }
  return result;
};
export function getPropByPath(obj: any, path: string, strict?: any) {
  let tempObj = obj;
  path = path.replace(/\[(\w+)\]/g, ".$1");
  path = path.replace(/^\./, "");

  let keyArr = path?.split(".");
  let i = 0;
  for (let len = keyArr.length; i < len - 1; ++i) {
    if (!tempObj && !strict) break;
    let key = keyArr[i];
    if (key in tempObj) {
      tempObj = tempObj[key];
    } else {
      if (strict) {
        throw new Error("please transfer a valid prop path to form item!");
      }
      break;
    }
  }
  return {
    o: tempObj,
    k: keyArr[i],
    v: tempObj ? tempObj[keyArr[i]] : null,
  };
}
export function deepClone(object: any) {
  if (typeof object !== "object" || object == null || isFunction(object))
    return object;
  let result: any = Array.isArray(object) ? [] : {};
  for (let key in object)
    if (object.hasOwnProperty(key)) result[key] = deepClone(object[key]);
  return result;
}
export function trimAll(ele: string) {
  if (typeof ele === "string") return ele?.split(/[\t\r\f\n\s]*/g).join("");
  else
    console.error(
      `${typeof ele} is not the expected type, but the string type is expected`
    );
}
export function upperFirst(str: string) {
  str = str.toLowerCase();
  return str.replace(/\b\w|\s\w/g, (fw: string) => fw.toUpperCase());
}
export function formatDate(timestamp = Date.now(), format = "Y-M-D h:m:s") {
  let date = new Date(timestamp);
  let dateInfo: any = {
    Y: date.getFullYear(),
    M: date.getMonth() + 1,
    D: date.getDate(),
    h: date.getHours(),
    m: date.getMinutes(),
    s: date.getSeconds(),
  };
  let formatNumber = (n: any) => (n >= 10 ? n : "0" + n);
  let res = format
    .replace("Y", dateInfo.Y)
    .replace("M", formatNumber(dateInfo.M))
    .replace("D", formatNumber(dateInfo.D))
    .replace("h", formatNumber(dateInfo.h))
    .replace("m", formatNumber(dateInfo.m))
    .replace("s", formatNumber(dateInfo.s));
  return res;
}
// 回显数据字典
export function selectDictLabel(options: any, value: any) {
  const _options = options?.value ?? options;
  if (value === undefined) {
    return "";
  }
  let actions: any = [];
  Object.keys(_options).some((key) => {
    if (_options[key].value + "" === "" + value) {
      actions.push(_options[key].label?.value ?? _options[key].label);
      return true;
    }
  });
  return actions.join("");
}
// 回显数据字典（字符串数组）
export function selectDictLabels(options: any, value: any, separator: any) {
  if (value === undefined) {
    return "";
  }
  let actions: any = [];
  let currentSeparator = undefined === separator ? "," : separator;
  let temp = value?.split(currentSeparator);
  Object.keys(value?.split(currentSeparator)).some((val) => {
    let match = false;
    Object.keys(options).some((key) => {
      if (options[key].value == "" + temp[val]) {
        actions.push(options[key].label + currentSeparator);
        match = true;
      }
    });
    if (!match) actions.push(temp[val] + currentSeparator);
  });
  return actions.join("").substring(0, actions.join("").length - 1);
}
/**
 * 产生随机整数，包含下限值，包括上限值
 * @param {Number} lower 下限
 * @param {Number} upper 上限
 * @return {Number} 返回在下限到上限之间的一个随机整数
 */
export function randomNumber(lower: number = 0, upper: number = 4294967295) {
  return Math.floor(Math.random() * (upper - lower + 1)) + lower;
}
export function randomString(length = 5) {
  var string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_";
  var result = "";
  for (var i = length; i > 0; --i)
    result += string[Math.floor(Math.random() * string.length)];
  return result;
}
export function generateRandomString(length = 5) {
  let characters = "0123456789abcdefghijklmnopqrstuvwxyz";
  let result = "";
  for (let i = 0; i < length; i++) {
    let randomIndex = Math.floor(Math.random() * characters.length);
    result += characters[randomIndex];
  }
  return result;
}
export const bindOnPrefix = (on: { [x: string]: any }, prefix = "on") => {
  if (!on) return;
  Object.keys(on).forEach((key) => {
    if (key.indexOf(prefix) < 0) {
      on[prefix + upperFirst(key)] = on[key];
      delete on[key];
    }
  });
  return on;
};
export const defineColumns = (columns: any) => {
  return (columns?.value ?? columns).map((item: any) => {
    item.align ??= "center";
    return item;
  });
};
export const arrayToOptions = (
  array = [],
  { label = "label", value = "value" } = {}
) => {
  if (!array?.length) return [];
  return array.map((item: any) => ({
    label: item?.[label],
    value: item?.[value],
  }));
};
export const objectToOptions = (object: any = {}, valueType = "string") => {
  if (isEmptyType(object)) return [];
  const tmpArray: any = Object.entries(object);
  const options: any = [];
  for (let [value, label] of tmpArray) {
    if (valueType === "string") value = value + "";
    if (valueType === "number") value = +value;
    options.push({ label, value });
  }
  return options;
};
export const getItemById: any = (
  data: any,
  id: any,
  {
    keys = ["tag_name", "tag_id"],
    values = ["name", "id"],
    node = "children",
  }: any = {}
) => {
  let result: any = null;
  function getTreeItem(data: any[], id: string | number) {
    if (isNumber(id) || isString(id)) {
      data?.map(
        (item: { [x: string]: any; id: string | number; children: any }) => {
          if (item[values[1]] == id)
            result = { [keys[0]]: item[values[0]], [keys[1]]: item[values[1]] };
          else if (item[node]) getTreeItem(item[node], id);
        }
      );
    }
  }
  getTreeItem(data, id);
  return result;
};
export const getItemsById = (
  data: any,
  ids: any[],
  {
    keys = ["tag_name", "tag_id"],
    values = ["name", "id"],
    node = "children",
  } = {}
) => {
  if (!isArray(ids)) return ids;
  let newArr: null[] = [];
  ids.forEach((id: any) => {
    newArr.push(
      getItemById(data, id, {
        keys,
        values,
        node,
      })
    );
  });
  return newArr;
};
export const clearObjAttr = (form: any) => {
  Object.keys(form).forEach((key) => {
    if (isObject(form[key])) form[key] = {};
    else if (isArray(form[key])) form[key] = [];
    else form[key] = undefined;
  });
};
export const resetObjAttr = (form: any) => clearObjAttr(form);
export const initObjAttr = (
  targetForm: any,
  originForm: any,
  basicKey = "origin",
  is_clearTargetFormAttr = true
) => {
  if (basicKey === "origin") {
    if (is_clearTargetFormAttr) deleteObjAttr(targetForm);
    Object.keys(originForm).forEach(
      (key) => (targetForm[key] = originForm[key])
    );
  }
  if (basicKey === "target")
    Object.keys(targetForm).forEach(
      (key) => (targetForm[key] = originForm[key] ?? targetForm[key])
    );
};
export const deleteObjAttr = (obj: any) => {
  if (isObject(obj)) Object.keys(obj).forEach((key) => delete obj[key]);
  if (isArray(obj)) obj.length = 0;
};
export const deleteArrAttr = (arr: any) => {
  arr.length = 0;
};
export function flatten(sourceArray, flattenedArray: any[] = []) {
  for (const element of sourceArray)
    if (Array.isArray(element)) flatten(element, flattenedArray);
    else flattenedArray.push(element);
  return flattenedArray;
}
export function getLastYear(yearNum = 1): any {
  let today = new Date();
  today.setFullYear(today.getFullYear() - yearNum);
  return today;
}
export function contains(arr: string | any[], val: any) {
  for (var i = 0; i < arr.length; i++) {
    if (isObject(arr[i])) return arr[i].hasOwnProperty(val);
    if (!isObject(arr[i]) && arr[i] === val) return true;
  }
  return false;
}
export const toLocalTime = (start_end: any, format = "YYYY-MM-DD HH:mm:ss") => {
  if (isEmptyType(start_end)) return [];
  return [
    $dayjs(start_end[0]).format(format),
    $dayjs(start_end[1]).format(format),
  ];
};
export const getFileExtension = (url: any) => {
  const dotIndex = url.lastIndexOf(".");
  const extension = url.substring(dotIndex + 1);
  if (/(jpg|jpeg|png)$/.test(extension.toLowerCase())) {
    return "img";
  } else if (/(mp4|avi|mov)$/.test(extension.toLowerCase())) {
    return "mp4";
  }
  return false;
};
export const clearObjectZeroValue = ({
  target = {},
  targetKeys = [],
}: any = {}) => {
  targetKeys.forEach((key: any) => {
    if (+target[key] === 0) target[key] = undefined;
  });
};
export function getTopDistance(element: any) {
  var distance = element?.offsetTop;
  while (element.offsetParent) {
    element = element?.offsetParent;
    distance += element?.offsetTop;
  }
  return distance;
}
export function toThousands(num: any) {
  if ((num + "").trim() == "") return "";
  if (isNaN(num)) return "";
  num = num + "";
  if (/^.*\..*$/.test(num)) {
    var pointIndex = num.lastIndexOf(".");
    var intPart = num.substring(0, pointIndex);
    var pointPart = num.substring(pointIndex + 1, num.length);
    intPart = intPart + "";
    var re = /(-?\d+)(\d{3})/;
    while (re.test(intPart)) {
      intPart = intPart.replace(re, "$1,$2");
    }
    num = intPart + "." + pointPart;
  } else {
    num = num + "";
    var re = /(-?\d+)(\d{3})/;
    while (re.test(num)) {
      num = num.replace(re, "$1,$2");
    }
  }
  return num;
}
export function delThousands(num: any) {
  num = num + "";
  if (num.trim() == "") return "";
  num = num.replace(/,/gi, "");
  return +num;
}
export const formatTime = (
  time: string | number | Date,
  format = "YYYY-MM-DD HH:mm:ss"
) => {
  return $dayjs(time).format(format);
};
export const debounce = (fn: Function, delay: number = 100) => {
  let timer: any = null;
  return function (...args: any[]) {
    if (timer) clearTimeout(timer);
    timer = setTimeout(fn.bind(null, ...args), delay);
  };
};
export function getBrowserLang() {
  const navigator = reactive<any>(window.navigator);
  let browserLang = (
    navigator.language ??
    navigator.userLanguage ??
    navigator.browserLanguage ??
    navigator.systemLanguage
  ).toLowerCase();
  return browserLang;
}
export const stringToColumns = (str: any) => {
  str = decodeURIComponent(str);
  const obj = isJSONParse(str) ? JSON.parse(str) : {};
  const keys = Object.keys(obj);
  return keys.map((key) => {
    if (key != "action") {
      return {
        title: obj[key],
        dataIndex: key,
        key: key,
      };
    } else {
      return {
        title: obj[key],
        key: key,
      };
    }
  });
};
export const filterOption = (inputValue: any, option: any) =>
  option.label.toString().toLowerCase().includes(inputValue.toLowerCase()) ||
  option.value.toString().toLowerCase().includes(inputValue.toLowerCase());
export function getTextWidth(text, fontSize: any = 14) {
  // 创建临时元素
  const _span = createElNode("span");
  // 放入文本
  _span.innerText = text;
  // 设置文字大小
  _span.style.fontSize = parseInt(fontSize) + "px";
  // span元素转块级
  _span.style.position = "absolute";
  // span放入body中
  document.body.appendChild(_span);
  // 获取span的宽度
  let width = _span.offsetWidth;
  // 从body中删除该span
  document.body.removeChild(_span);
  // 返回span宽度
  return width;
}
export function getDomStyle(domNode, name) {
  const win: any = window;
  if (win.getComputedStyle) {
    //谷歌/edge浏览器，具有getComputedStyle()方法
    return getComputedStyle(domNode, null)[name];
  } else {
    //IE没有getComputedStyle()方法，下面为IE8的方式
    return domNode.currentStyle[name];
  }
}
export const setDomAttr = (domNode, key = "data-", value) =>
  domNode.setAttribute(key, value);

export const getDomAttr = (domNode, key = "data-") =>
  domNode.getAttribute(key) ||
  domNode.dataset[key.split("-").slice(1).join("-")];
export const removeDomAttr = (domNode, key = "data-") =>
  domNode.removeAttribute(key);
// 截取视频的第一帧
export const getVideoFirstFrame = (videoUrl: any) => {
  // 创建video元素
  const video: any = createElNode("video");
  video.src = videoUrl;
  video.setAttribute("crossOrigin", "Anonymous"); // 处理跨域
  video.setAttribute("preload", "auto"); // auto|metadata|none
  video.muted = true;
  video.autoplay = true;
  video.preload = true;
  // 等待视频加载完成
  return new Promise((resolve, reject) => {
    video.addEventListener("loadedmetadata", () => {
      // 这里开始播放
      video.play();
      setTimeout(() => {
        // 过500ms 暂停， 解决空白问题
        video.pause();
        // 创建canvas元素
        const canvas = createElNode("canvas");
        canvas.width = video.videoWidth;
        canvas.height = video.videoHeight;
        // 将视频帧绘制到canvas上
        const ctx: any = canvas.getContext("2d");
        console.log(video);
        ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
        // 将canvas图像转换为base64格式的数据URI
        const dataUrl = canvas.toDataURL("image/png");
        // 返回base64格式的数据URI
        resolve(dataUrl);
      }, 500);
    });

    // 如果视频加载出错，则返回错误信息
    video.addEventListener("error", () => {
      reject(`Failed to load video: ${videoUrl}`);
    });
  });
};
// 根据系统选择时区转换时间
export function getTimeByZone(
  time: string | number | Date,
  format = "YYYY-MM-DD HH:mm:ss"
) {
  if (!time) return;
  if (isNumberString(time) || isNumber(time)) time = formatTime(time, format);
  if (sysZone.value === "UTC") {
    const utc_to_local = moment.utc(time).local().format(format);
    const local_to_utc = moment(utc_to_local).utc().format(format);
    return local_to_utc;
  }
  return moment.tz(moment.utc(time), sysZone.value).format(format);
}
// 将时间根据系统选择时区转换为UTC时间
export function getUTCTimeByzone(time: string | number | Date) {
  if (!time) return;
  // 不包含时间不转换
  if (typeof time === "string" && time.indexOf(":") === -1) return time;
  const date = new Date(time);
  const timeZone =
    sysZone.value === 99 ? date.getTimezoneOffset() / 60 : sysZone.value;
  const utcTime = date.getTime() + 3600000 * timeZone;
  return formatTime(utcTime);
}
export const DiagonalToHorizontal = (string: string, isReverse = false) => {
  if (isReverse)
    return string.split("/").filter(Boolean).reverse().join("-").toLowerCase();
  return string.split("/").filter(Boolean).join("-").toLowerCase();
};
export const DiagonalToUnderline = (string: string) =>
  string.split("/").filter(Boolean).join("_").toLowerCase();
export const SmallHumpToUnderline = (string: string) =>
  string.replace(/([A-Z])/g, "_$1").toLowerCase();
export const copyText = (text: string) => {
  return new Promise((resolve, reject) => {
    if (navigator.clipboard)
      navigator.clipboard
        .writeText(text)
        .then(() => resolve(true))
        .catch((err) => reject(err));
    else {
      const input = document.createElement("input");
      input.setAttribute("readonly", "readonly");
      input.setAttribute("value", text);
      document.body.appendChild(input);
      input.select();
      input.setSelectionRange(0, 9999);
      if (document.execCommand("copy")) resolve(true);
      else reject(false);
      document.body.removeChild(input);
    }
  });
};
export const isDevEnv = computed(() =>
  import.meta.env.VITE_ENV.startsWith("development")
);
export const isProdEnv = computed(() =>
  import.meta.env.VITE_ENV.startsWith("production")
);
export const isStartDev = computed(
  () => import.meta.env.VITE_ENV === "development.dev"
);
export const isStartTest = computed(
  () => import.meta.env.VITE_ENV === "development.test"
);
export const isBuildTest = computed(
  () => import.meta.env.VITE_ENV === "production.test"
);
export const isBuildProd = computed(
  () => import.meta.env.VITE_ENV === "production.prod"
);
